
// (ERLANG)/doc/tutorial/port_driver.c

library example_drv;

uses
  funcs,
  Erl_Driver;

type
  example_data = packed record
    port: ErlDrvPort;
  end;

function example_drv_start(port: ErlDrvPort; buff: PAnsiChar): ErlDrvData; cdecl;
var
  d : ^example_data;
begin
  d := driver_alloc(sizeof(example_data));
  d.port := port;
  Result :=  ErlDrvData(d);
end;

procedure example_drv_stop(handle: ErlDrvData); cdecl;
begin
  driver_free(handle);
end;

procedure example_drv_output(handle:ErlDrvData; buff:PAnsiChar; bufflen:Integer); cdecl;
var
  d : ^example_data;
  fn, arg: PByte;
  res: Byte;
begin
  d := pointer(handle);

(* bufflen is 2
  buff has a list, encoded in complex5.erl  ==>
     encode({foo, X}) -> [1, X];
     encode({bar, Y}) -> [2, Y].
*)
  fn := @buff[0];       // func index
  arg := @buff[1];      // parament
  case fn^ of
    1 : res := foo(arg^);
    2 : res := bar(arg^);
  end;

  driver_output(d.port, @res, sizeof(res));
end;

var
  example_driver_entry : ErlDrvEntry = (
    start  : example_drv_start;
    stop   : example_drv_stop;
    output : example_drv_output;
    driver_name : 'example_drv';
  );

function _DRIVER_INIT(DrvName: PAnsiChar): PErlDrvEntry;
begin
  // (optional, )rewrite driver_name, support change the dll's name in file system.
  if assigned(DrvName) then
    example_driver_entry.driver_name := DrvName;
  Result := @example_driver_entry;
end;

begin
  DRIVER_INIT_BY_USER := _DRIVER_INIT;
end.
